package com.liruo.springframework.core.aop.aspectj;

import java.util.ArrayList;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
public class _02_AdviceCycleAspect {

  public static final List<String> CYCLE = new ArrayList<>(5);
  public static final String CHANGE_RESULT_PREFIX = Around.class.getSimpleName() + ": ";

  @Around(
      value = "execution(String com.liruo.springframework.core.aop.aspectj.AspectAnnotationTarget.simpleMethod(..))"
  )
  public Object around(ProceedingJoinPoint point) throws Throwable {
    CYCLE.add(Around.class.getSimpleName() + "Before");
    Object result = point.proceed(point.getArgs());
    CYCLE.add(Around.class.getSimpleName() + "After");
    return CHANGE_RESULT_PREFIX + result;
  }

  @Before(
      value = "execution(String com.liruo.springframework.core.aop.aspectj.AspectAnnotationTarget.simpleMethod(..))"
  )
  public void before(JoinPoint point) {
    CYCLE.add(Before.class.getSimpleName());
  }

  @AfterReturning(
      value = "execution(String com.liruo.springframework.core.aop.aspectj.AspectAnnotationTarget.simpleMethod(..))",
      returning = "retVal"
  )
  public void afterReturning(JoinPoint point, Object retVal) {
    CYCLE.add(AfterReturning.class.getSimpleName());
    log.info("{}, retVal={}", AfterReturning.class.getName(), retVal);
  }

  @AfterThrowing(
      value = "execution(String com.liruo.springframework.core.aop.aspectj.AspectAnnotationTarget.simpleMethod(..))",
      throwing = "ex"
  )
  public void afterThrowing(JoinPoint point, Throwable ex) {
    CYCLE.add(AfterThrowing.class.getSimpleName());
    log.info("{}, ex=", AfterThrowing.class.getName(), ex);
  }

  @After(
      value = "execution(String com.liruo.springframework.core.aop.aspectj.AspectAnnotationTarget.simpleMethod(..))"
  )
  public void after(JoinPoint point) {
    CYCLE.add(After.class.getSimpleName());
  }
}
